package com.jack.serialport;

import android.util.Log;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.security.InvalidParameterException;

/**
 * 操作串口helper类
 */
public class SerialPortHelper {
    private static final String TAG = SerialPortHelper.class.getSimpleName();
    private static volatile SerialPortHelper single;

    private SerialPort mSerialPort;
    private OutputStream mOutputStream;
    private InputStream mInputStream;
    private ReadThread mReadThread;
    private String mPort;
    private int mBaudRate = -1;
    private static boolean mIsOpen = false;

    public static SerialPortHelper getInstance() {
        if (null == single) {
            synchronized (SerialPortHelper.class) {
                if (null == single) {
                    single = new SerialPortHelper();
                }
            }
        }
        return single;
    }

    private SerialPortHelper() {
        this.mPort = "/dev/ttyS3";//GetTtyUsbPath();
        this.mBaudRate = 9600;
        Log.e(TAG, "final path: " + mPort);
    }

    public String GetTtyUsbPath(){
        String root = "/sys/bus/usb/devices/";
        File dev = new File(root);
        File[] files = dev.listFiles();
        for(int i = 0;i < files.length;++i){
            if(files[i].isDirectory()){
                File fProduct = new File(files[i].getAbsolutePath() + "/idProduct");
                File fVendor = new File(files[i].getAbsolutePath() + "/idVendor");
                if(fProduct.exists() && fVendor.exists()){
                    try {
                        LineNumberReader readerProduct = new LineNumberReader(new FileReader(fProduct));
                        String pidVersion = readerProduct.readLine();
                        Log.e(TAG, "jack pid = " + pidVersion);
                        readerProduct.close();

                        LineNumberReader readerVendor = new LineNumberReader(new FileReader(fVendor));
                        String vidVersion = readerVendor.readLine();
                        Log.e(TAG, "jack vid = " + vidVersion);
                        readerVendor.close();

                        if(pidVersion != null && pidVersion.equals("7523") && vidVersion != null && vidVersion.equals("1a86")){
                            File fdev = new File(files[i].getAbsolutePath());
                            Log.e(TAG, "file path: " + files[i].getAbsolutePath());
                            File[] f = fdev.listFiles();
                            for(int j = 0;j < f.length;++j){
                                if(f[j].isDirectory() && f[j].getName().startsWith(files[i].getName())){
                                    File ttyDev = new File(f[j].getAbsolutePath());
                                    File[] fTty = ttyDev.listFiles();
                                    for (int k = 0;k < fTty.length;++k){
                                        if(fTty[k].getName().startsWith("ttyUSB") && isTTYExist(fTty[k].getName())){
                                            Log.e(TAG, "#####:" + fTty[k].getName());
                                            return "/dev/" + fTty[k].getName();
                                        }
                                    }
                                }
                            }

                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
        return "/dev/ttyUSB12";
    }

    private boolean isTTYExist(String ttyUsb) {
        String root = "/dev/";
        File dev = new File(root);
        File[] files = dev.listFiles();
        for(int i = 0;i < files.length;++i){
            if (!files[i].isDirectory() && files[i].getName().startsWith(ttyUsb)) {
                return true;
            }
        }
        return false;
    }

    public void open() throws SecurityException, IOException, InvalidParameterException {
        mSerialPort = new SerialPort(new File(mPort), mBaudRate, 0);
        mOutputStream = mSerialPort.getOutputStream();
        mInputStream = mSerialPort.getInputStream();
        if (mReadThread == null) {
            mReadThread = new ReadThread();
            mReadThread.start();
        }

        if (mOutputStream != null && mInputStream != null) {
            mIsOpen = true;
        } else {
            Log.e(TAG, "open serial port err. ");
        }
    }

    public void open2() throws SecurityException, IOException, InvalidParameterException {
        mSerialPort = new SerialPort(new File(mPort), mBaudRate, 0, 8, 1);
        mOutputStream = mSerialPort.getOutputStream();
        mInputStream = mSerialPort.getInputStream();
        if (mReadThread == null) {
            mReadThread = new ReadThread();
            mReadThread.start();
        }

        if (mOutputStream != null && mInputStream != null) {
            mIsOpen = true;
        } else {
            Log.e(TAG, "open serial port err. ");
        }
    }

    public void close() {
        try {
            if (mReadThread != null) {
                mReadThread.interrupt();
            }
            if (mInputStream != null) {
                mInputStream.close();
                mInputStream = null;
            }
            if (mOutputStream != null) {
                mOutputStream.close();
                mOutputStream = null;
            }
            if (mSerialPort != null) {
                mSerialPort.close();
                mSerialPort = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        mIsOpen = false;
    }

    public boolean isOpen() {
        return mIsOpen;
    }

    public synchronized void sendTxt(String sTxt) {
        sTxt = sTxt.replace(" ", "");
        byte[] bOutArray = sTxt.getBytes();
        send(bOutArray);
    }

    public int sendHex(String sHex) {
        sHex = sHex.replace(" ", "");
        byte[] bOutArray = MyFunc.HexToByteArr(sHex);
        return send(bOutArray);
    }

    private long start2, end2;//10秒打印一条log
    public synchronized int send(final byte[] bOutArray) {
        try {
            if (!mIsOpen){
                open();
            }
            if (mIsOpen) {
                String res = Tool.printByteToString(bOutArray);
                res = res.trim().toUpperCase();

                Log.i(TAG, "send data: " + res);

                mOutputStream.write(bOutArray);
                mOutputStream.flush();
                Thread.sleep(50);
            } else {
                Log.i(TAG, "comm is closed");
            }
        } catch (InterruptedException e) {
            return -1;
        } catch (Exception e) {
            e.printStackTrace();
            return -2;
        }
        return 0;
    }

    private class ReadThread extends Thread {
        @Override
        public void run() {
            super.run();
            try {
                read(!isInterrupted());
                //readNonBlock();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void read(boolean notInterrupted) throws IOException {
        if (mInputStream == null) {
            return;
        }

        byte[] buff = new byte[1024];
        int len;
        String resultData = "";
        while (notInterrupted && ((len = mInputStream.read(buff)) != -1)) {
            byte[] temp = new byte[len];
            System.arraycopy(buff, 0, temp, 0, len);
            resultData = Tool.ByteToString(temp);
            resultData = resultData.trim().toUpperCase();

            Log.e(TAG, "received data:" + resultData);

            try { Thread.sleep(10); } catch (Exception err){}
        }
    }
}